package com.yum.Iterator.Map.YAbstractMap;

import com.yum.Iterator.Collection.YCollection;
import com.yum.Iterator.Iterable.YIterable;
import com.yum.Iterator.Map.YMap;
import com.yum.Iterator.Set.YSet;
import com.yum.Iterator.YIterator;

import java.io.Serializable;
import java.util.AbstractMap;
import java.util.Iterator;

public abstract class YAbstractMap<K,V> implements YMap<K,V> {

    transient YSet<K> keySet;
    transient YCollection<V> values;

    @Override
    public V get(K key) {
        for(YEntry<K,V> kvyEntry:entrySet()){
            if(compare(key,kvyEntry.getKey())){
                return kvyEntry.getValue();
            }
        }
        return null;
    }

    @Override
    public YCollection<V> values() {
        return values;
    }

    @Override
    public YSet<K> keySet() {
        return keySet;
    }

    @Override
    public abstract V put(K key, V value);

    @Override
    public void putAll(YMap<? extends K, ? extends V> m) {
        for(YEntry<? extends K,? extends V> kvyEntry:m.entrySet()){
            put(kvyEntry.getKey(),kvyEntry.getValue());
        }
    }

    @Override
    public abstract YSet<YEntry<K, V>> entrySet();

    @Override
    public String toString() {
        Iterator<YEntry<K,V>> i = entrySet().iterator();
        return !i.hasNext()?"{}": mapData(i);
    }

    @Override
    public boolean contatinsValue(V value) {
        if(value == null){
            for(YEntry<K,V> kvyEntry:entrySet()){
                if(kvyEntry.getValue() == null)
                    return true;
            }
        }
        else {
            for(YEntry<K,V> kvyEntry:entrySet()){
                if(kvyEntry.getValue().equals(value))
                    return true;
            }
        }
        return false;
    }

    @Override
    public boolean containsKey(K key) {
        if(key == null){
            for(YEntry<K,V> kvyEntry:entrySet()){
                if(kvyEntry.getKey() == null){
                    return true;
                }
            }
        }
        else {
            for(YEntry<K,V> kvyEntry:entrySet()){
                if(kvyEntry.getKey().equals(key)){
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    @Override
    public int hashCode() {
        int h = 0;
        for (YEntry<K, V> kvyEntry : entrySet()) {
            h += kvyEntry.hashCode();
        }
        return h;

    }

    @Override
    public void clear() {
        entrySet().clear();
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    public static class YoHaNeEntry<K,V> implements YEntry<K,V>, Serializable {

        private static final long serialVersionUID = 5057010741152683368L;

        private final K key;

        private V value;

        public YoHaNeEntry(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public YoHaNeEntry(YEntry<? extends K,? extends V> yEntry){
            this.key = yEntry.getKey();
            this.value = yEntry.getValue();
        }

        @Override
        public K getKey() {
            return key;
        }

        @Override
        public V getValue() {
            return value;
        }

        @Override
        public V setValue(V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        @Override
        public int hashCode() {
            return ((key==null)?0:(key.hashCode())) ^
                    ((value==null)?0:(value.hashCode()));
        }

        @Override
        public String toString() {
            return key+"="+value;
        }

        @Override
        public boolean equals(Object obj) {
            if(!(obj instanceof YEntry))
                return false;
            YEntry<?,?> e = (YEntry<?, ?>) obj;
            return (key == null?e.getKey() == null:key.equals(e.getKey()))
                    && (value==null?e.getValue()==null:value.equals(e.getKey()));
        }
    }

    public static boolean compare(Object obj,Object value){
        return obj == null ? value == null:obj.equals(value);
    }


    private String mapData(Iterator<YEntry<K,V>> i){
        StringBuilder sb = new StringBuilder("{");
        while (true){
            YEntry<K,V> e = i.next();
            sb.append(e.getKey());
            sb.append("=");
            sb.append(e.getKey());
            if(!i.hasNext()){
                sb.append("}");
                return sb.toString();
            }
            sb.append(", ");
        }
    }
}
